package com.sam.spring.security.config;

import com.sam.spring.security.compent.CustomExpiredSessionStrategy;
import com.sam.spring.security.compent.CustomLogoutSuccessHandler;
import com.sam.spring.security.compent.CustomRbacService;
import com.sam.spring.security.compent.CustomUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

/**
 * @classname: MyWebSecurityConfig
 * @description: TODO
 * @Author: sam
 * @date: 2021/6/27 17:06
 */
@Configuration
@EnableWebSecurity
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    CustomLogoutSuccessHandler customLogoutSuccessHandler;

    @Autowired
    private AuthenticationSuccessHandler customAuthenticationSuccessHandler;

    @Autowired
    private AuthenticationFailureHandler customAuthenctiationFailureHandler;

    @Autowired
    CustomUserDetailService customUserDetailService;

    @Autowired
    CustomRbacService customRbacService;

    String role_user="USER";
    String role_admin="ADMIN";
    String role_dba="DBA";

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        /*
         * 配置为从内存中进行加载认证信息.
         * 首先配直了三个用户， root 用户具备 ADMIN 和 DBA 的角色， a伽m 用户具备 ADMIN 和USER 的角色， sang 用户具备 USER 的角色 。
         */
        /*auth.inMemoryAuthentication()
                .withUser("root").password(passwordEncoder().encode("123")).roles(role_admin,role_dba)
                .and()
                .withUser("admin").password(passwordEncoder().encode("123")).roles(role_admin,role_user)
                .and()
                .withUser("sang").password(passwordEncoder().encode("123")).roles(role_user);*/

        auth.userDetailsService(customUserDetailService);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/login.html","/login","/code").permitAll()
                .anyRequest().access("@customRbacService.hasPermission(request,authentication)")
                /*.antMatchers("/admin/**")
                .hasRole("ADMIN")
                .antMatchers("/user/**")
                .access("hasAnyRole('ADMIN','USER')")
                .antMatchers("/dba/**")
                .access("hasRole('ADMIN') and hasRole('DBA')")
                // 除了前面定义的 URL 模式之外，用户访问其他的 URL 都必须认证后访问（登录后访问）。
                .anyRequest()
                .authenticated()*/
                .and()
                //表示和登录相关的接口都不需要认证即可访问。
                .formLogin()
                .loginPage("/login")
                .loginProcessingUrl("/doLogin")
                .successHandler(customAuthenticationSuccessHandler)
                .failureHandler(customAuthenctiationFailureHandler)
                .permitAll()
                .and()
                .logout()
                .logoutUrl("/logout")
                .clearAuthentication(true)
                .invalidateHttpSession(true)
                .logoutSuccessHandler(customLogoutSuccessHandler)
                .and()
                .sessionManagement()
                .maximumSessions(1)
                .maxSessionsPreventsLogin(false)
                .expiredSessionStrategy(new CustomExpiredSessionStrategy())
                ;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        // 设置默认的加密方式（强hash方式加密）
        return new BCryptPasswordEncoder();
    }
    /*@Bean
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }*/
}
